diff options
| author | joonhoekim <26rote@gmail.com> | 2025-12-08 12:08:00 +0900 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-12-08 12:08:00 +0900 |
| commit | 71c0ba1f01b98770ec2c60cdb935ffb36c1830a9 (patch) | |
| tree | 01b5dab4888f865d605c46d41896a2432e53015f /app/[lng]/test | |
| parent | 298e166eebeba3276403f14f9b9b1e3f8f3d735e (diff) | |
(김준회) 테이블 커스텀 훅 버전 생성
Diffstat (limited to 'app/[lng]/test')
| -rw-r--r-- | app/[lng]/test/table-v3/page.tsx | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/app/[lng]/test/table-v3/page.tsx b/app/[lng]/test/table-v3/page.tsx new file mode 100644 index 00000000..eccf7cff --- /dev/null +++ b/app/[lng]/test/table-v3/page.tsx @@ -0,0 +1,188 @@ +"use client"; + +import * as React from "react"; +import { useClientTable, ClientVirtualTable } from "@/components/client-table-v3"; +import { productColumns } from "../table-v2/columns"; +import { + getProductTableData, + getAllProducts, + getProductTableDataWithGrouping, + GroupInfo +} from "../table-v2/actions"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { ChevronDown, ChevronRight } from "lucide-react"; + +// --- Components for Examples --- + +function ClientSideExample() { + const [products, setProducts] = React.useState<any[]>([]); + + // Load initial data once + React.useEffect(() => { + getAllProducts().then(setProducts); + }, []); + + // Hook handles table state + const { table, isLoading } = useClientTable({ + fetchMode: "client", + data: products, + columns: productColumns, + enablePagination: true, + enableGrouping: true, + }); + + return ( + <Card> + <CardHeader> + <CardTitle>Pattern 1: Client-Side (V3)</CardTitle> + <CardDescription> + Uses `useClientTable` hook for simplified state management. + </CardDescription> + </CardHeader> + <CardContent className="h-[500px]"> + <ClientVirtualTable + table={table} + isLoading={isLoading} + enableUserPreset + tableKey="v3-client-pattern" + /> + </CardContent> + </Card> + ); +} + +function ServerFactoryExample() { + // Hook handles everything: state, fetching, debouncing + const { table, isLoading } = useClientTable({ + fetchMode: "server", + fetcher: getProductTableData, + columns: productColumns, + enablePagination: true, + enableUserPreset: true, // We can enable this in options too? No, hook doesn't care. Component cares. + }); + + return ( + <Card> + <CardHeader> + <CardTitle>Pattern 2: Factory Service (V3)</CardTitle> + <CardDescription> + Zero boilerplate state management in the component. + </CardDescription> + </CardHeader> + <CardContent className="h-[500px]"> + <ClientVirtualTable + table={table} + isLoading={isLoading} + enableUserPreset + tableKey="v3-server-pattern" + /> + </CardContent> + </Card> + ); +} + +function ServerGroupingExample() { + // Adapter for V2 fetcher signature to work with V3 hook + // The V2 action expects (state, expandedGroups), but V3 hook passes (state). + // We wrap it to extract expandedGroups from state.expanded. + const fetcher = React.useCallback((state: any) => { + const expanded = state.expanded || {}; + // Convert TanStack ExpandedState { [key]: true } to string[] + const expandedKeys = Object.keys(expanded).filter(k => expanded[k]); + return getProductTableDataWithGrouping(state, expandedKeys); + }, []); + + // Pattern 2-B support + const { + table, + isLoading, + isServerGrouped, + serverGroups, + refresh, + } = useClientTable({ + fetchMode: "server", + fetcher, + columns: productColumns, + enablePagination: true, + enableGrouping: true, + }); + + // When serverGroups change (new grouping), reset expansion + // (In a real app, you might want to persist expansion logic in the fetcher wrapper or hook) + + return ( + <Card> + <CardHeader> + <CardTitle>Pattern 2-B: Server Grouping (V3)</CardTitle> + <CardDescription> + Hook manages state, Component manages Custom Rendering for Groups. + </CardDescription> + </CardHeader> + <CardContent className="h-[500px] flex flex-col"> + {/* We need the toolbar even in grouped mode */} + <div className="mb-4 p-2 border rounded bg-muted/20"> + <p className="text-sm text-muted-foreground"> + Group by a column (Category, Status, IsNew) to see server grouping. + </p> + </div> + + {isServerGrouped ? ( + <div className="overflow-auto border rounded-md p-4 space-y-2"> + {serverGroups.map((group: GroupInfo) => ( + <div key={group.groupKey} className="border rounded p-2"> + <div className="font-bold flex items-center gap-2"> + <Badge variant="outline">{String(group.groupValue)}</Badge> + <span>({group.count})</span> + </div> + {/* Rows would go here */} + </div> + ))} + </div> + ) : ( + <ClientVirtualTable + table={table} + isLoading={isLoading} + enableUserPreset + tableKey="v3-server-grouping" + /> + )} + </CardContent> + </Card> + ); +} + +export default function TableV3Page() { + return ( + <div className="container py-8 space-y-8"> + <div> + <h1 className="text-3xl font-bold">ClientVirtualTable V3 DX Demo</h1> + <p className="text-muted-foreground"> + Demonstrating the new `useClientTable` hook for improved Developer Experience. + </p> + </div> + + <Tabs defaultValue="client"> + <TabsList> + <TabsTrigger value="client">Client-Side</TabsTrigger> + <TabsTrigger value="server">Server Factory</TabsTrigger> + <TabsTrigger value="grouping">Server Grouping</TabsTrigger> + </TabsList> + + <TabsContent value="client"> + <ClientSideExample /> + </TabsContent> + + <TabsContent value="server"> + <ServerFactoryExample /> + </TabsContent> + + <TabsContent value="grouping"> + <ServerGroupingExample /> + </TabsContent> + </Tabs> + </div> + ); +} + |
